home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / plan / src / mondraw.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  23KB  |  820 lines

  1. /*
  2.  * Main calendar window widgets.
  3.  *
  4.  *    clicked_calendar(x, y)        Press in calendar day box detected,
  5.  *                    pop up a one-day list menu
  6.  *    draw_month_year()        Draw the month and year into the
  7.  *                    main calendar window
  8.  *    draw_calendar()            Draw day grid into the main calendar
  9.  *                    window
  10.  *    draw_day(day)            Draw one day box into the day grid
  11.  *                    in the main calendar window
  12.  *    draw_day_notes(day)        Draw just the notes under the day
  13.  *                    number into a day box
  14.  *
  15.  *    date_to_time(day, month, year, wkday, yday, weeknum)
  16.  *                    Returns day/month/year as # of secs
  17.  *                    since 1/1/70, the weekday (0..6), the
  18.  *                    julian date (0..365), and the week #.
  19.  *    day_to_pos(x, y, day)        Return the position of the day box
  20.  *                    for a particular day.
  21.  *    pos_to_day(day, x, y)        Reverse operation, convert position
  22.  *                    to day number.
  23.  */
  24.  
  25. #include <time.h>
  26. #include <Xm/Xm.h>
  27. #ifdef JAPAN
  28. #include <jctype.h>
  29. #include <locale.h>
  30. #endif
  31. #include "cal.h"
  32.  
  33. #undef FULLWEEKS    /* if this is defined, the first complete week in */
  34.             /* January is counted as week 1. If it is undefined, */
  35.             /* the first partial week is counted as 1. */
  36.  
  37. extern char *mknotestring(), *mktimestring();
  38. extern char *parse_holidays();
  39. extern time_t tm_to_time();
  40. extern struct tm *time_to_tm();
  41. extern time_t get_time();
  42. extern BOOL lookup_entry(), lookup_next_entry();
  43. static BOOL set_day_bkg_color();
  44. time_t date_to_time();
  45.  
  46. #ifdef JAPAN
  47. static int        mixedstrtok();
  48. extern char        *localename;    /* locale name */
  49. extern unsigned short    (*kanji2jis)();    /* kanji2jis == euc2jis or sjis2jis */
  50. #endif
  51. extern Display        *display;    /* everybody uses the same server */
  52. extern GC        jgc, gc;    /* graphic context, Japanese and std */
  53. extern XFontStruct    *font[NFONTS];    /* fonts: FONT_* */
  54. extern struct mainmenu    mainmenu;    /* all important main window widgets */
  55. extern struct config    config;        /* global configuration data */
  56. extern int        curr_month;    /* month being displayed, 0..11 */
  57. extern int        curr_year;    /* year being displayed, since 1900 */
  58. extern time_t        curr_week;    /* week being displayed, time in sec */
  59. extern struct list    *mainlist;    /* list of all schedule entries */
  60. extern struct holiday    holiday[366];    /* info for each day, separate for */
  61. extern struct holiday    sm_holiday[366];/* full-line texts under, and small */
  62. extern short        monthbegin[12];    /* julian date each month begins with*/
  63. extern short        monthlen[];    /* length of each month */
  64.  
  65.                     /* most recent popup made for: (only */
  66.                     /* used to keep track of yellow box) */
  67. int            edit_month;    /*  month being edited, 0..11 */
  68. int            edit_year;    /*  year being edited, since 1900 */
  69. int            edit_day;    /*  day being edited, 1..31 or 0 */
  70.  
  71. extern char *weekday_name[];
  72. extern char *monthname[];
  73.  
  74.  
  75. /*
  76.  * got a click in the calendar area. If it's in a grid box with a valid
  77.  * day init, "edit" it by storing its day number in the edit_* variables.
  78.  * The previously edited day, and the new edited day are redrawn to move
  79.  * the yellow highlight. If the user clicked to the left of the calendar,
  80.  * create a week view.
  81.  * Also, create a day popup menu.
  82.  */
  83.  
  84. clicked_calendar(x, y)
  85.     int            x, y;        /* pixel pos clicked */
  86. {
  87.     int            day;
  88.     time_t            time;        /* time of day box, in sec */
  89.     int            sm = config.smallmonth;
  90.  
  91.     if (x < config.calbox_marg[sm] + config.calbox_arrow[sm]) {
  92.         struct tm tm;
  93.         int xtest, ytest;
  94.         y -= config.calbox_marg[sm] + config.calbox_title[sm];
  95.         y /= config.calbox_ys[sm];
  96.         (void)day_to_pos(&xtest, &ytest, 1);
  97.         tm.tm_year = curr_year;
  98.         tm.tm_mon  = curr_month;
  99.         tm.tm_mday = 7 * y - xtest +1;
  100.         tm.tm_hour = 0;
  101.         tm.tm_min  = 0;
  102.         tm.tm_sec  = 0;
  103.         if (tm.tm_mday < 1) {
  104.             if (!tm.tm_mon--)
  105.                 return;
  106.             tm.tm_mday += monthlen[tm.tm_mon] +
  107.                     (tm.tm_mon==1 && !(tm.tm_year&3));
  108.         }
  109.         if ((time = tm_to_time(&tm)) != (time_t)-1) {
  110.             curr_week = time;
  111.             create_week_menu();
  112.         }
  113.         return;
  114.     }
  115.     if (!pos_to_day(&day, x, y) || day == edit_day)
  116.         return;
  117.     if (edit_day) {
  118.         int oldday = edit_day;
  119.         edit_day = 0;
  120.         draw_day(oldday);
  121.         draw_year_day(oldday, edit_month, edit_year);
  122.         draw_week_day(oldday, edit_month, edit_year);
  123.     }
  124.     edit_day   = day;
  125.     edit_month = curr_month;
  126.     edit_year  = curr_year;
  127.     draw_day(edit_day);
  128.     draw_year_day(edit_day, edit_month, edit_year);
  129.     draw_week_day(edit_day, edit_month, edit_year);
  130.     if (time = date_to_time(day, curr_month, curr_year, 0, 0, 0))
  131.         create_list_popup(mainlist, time,
  132.                 (time_t)0, (char *)0, (struct entry *)0);
  133. }
  134.  
  135.  
  136. /*-------------------------------------------------- drawing ----------------*/
  137. /*
  138.  * draw the weekday names, depending on the Sunday-first flag
  139.  */
  140.  
  141. draw_month_year()
  142. {
  143.     print_button(mainmenu.month, monthname[curr_month]);
  144.     print_button(mainmenu.year, "%d", curr_year+1900);
  145. }
  146.  
  147.  
  148. /*
  149.  * draw all day boxes
  150.  */
  151.  
  152. draw_calendar()
  153. {
  154.     register struct config    *c = &config;
  155.     Window            window;
  156.     XRectangle        rects[7+8], *r = rects;
  157.     XPoint            point[4];
  158.     int            i, j;
  159.     int            sm = c->smallmonth;
  160.  
  161.     if (!mainmenu.cal)
  162.         return;
  163.     window = XtWindow(mainmenu.cal);
  164.     set_color(COL_CALBACK);                /* clear */
  165.     XFillRectangle(display, window, gc, 0, 0,
  166.         2*c->calbox_marg[sm] + c->calbox_xs[sm] * 7
  167.                      + c->calbox_arrow[sm],
  168.         2*c->calbox_marg[sm] + c->calbox_ys[sm] * 6
  169.                      + c->calbox_title[sm]);
  170.  
  171.                             /* vert lines */
  172.     for (i=0; i < 8; i++, r++) {
  173.         r->x      = c->calbox_marg[sm] + i * c->calbox_xs[sm]
  174.                            + c->calbox_arrow[sm];
  175.         r->y      = c->calbox_marg[sm] + c->calbox_title[sm];
  176.         r->width  = 3;
  177.         r->height = c->calbox_ys[sm] * 6;
  178.     }
  179.                             /* horz lines */
  180.     for (i=0; i < 7; i++, r++) {
  181.         r->x      = c->calbox_marg[sm] + c->calbox_arrow[sm];
  182.         r->y      = c->calbox_marg[sm] + c->calbox_title[sm]
  183.                            + c->calbox_ys[sm] * i;
  184.         r->width  = c->calbox_xs[sm] * 7 + 3;
  185.         r->height = 3;
  186.     }
  187.     set_color(COL_GRID);
  188.     XFillRectangles(display, window, gc, rects, 7+8);
  189.     set_color(COL_CALFRAME);
  190.     XDrawRectangle(display, window, gc,
  191.             c->calbox_marg[sm] + c->calbox_arrow[sm] -1,
  192.             c->calbox_marg[sm] + c->calbox_title[sm] -1,
  193.             c->calbox_xs[sm] * 7 + 4,
  194.             c->calbox_ys[sm] * 6 + 4);
  195.  
  196.     point[3].x =                    /* week call arrows */
  197.     point[0].x =
  198.     point[1].x = c->calbox_marg[sm]/2 +1;
  199.     point[2].x = point[0].x + c->calbox_arrow[sm] -1;
  200.     point[2].y = c->calbox_marg[sm] + c->calbox_title[sm]
  201.                     + c->calbox_ys[sm] / 2;
  202.     point[3].y =
  203.     point[0].y = point[2].y - (point[2].x - point[0].x);
  204.     point[1].y = point[2].y + (point[2].x - point[0].x);
  205.     if (c->calbox_arrow[sm] > 3)
  206.         for (i=0; i < 6; i++) {
  207.             set_color(COL_CALSHADE);
  208.             XFillPolygon(display, window, gc, point, 3, Convex,
  209.                             CoordModeOrigin);
  210.             set_color(COL_STD);
  211.             XDrawLines(display, window, gc, point, 4,
  212.                             CoordModeOrigin);
  213.             point[0].y += c->calbox_ys[sm];
  214.             point[1].y += c->calbox_ys[sm];
  215.             point[2].y += c->calbox_ys[sm];
  216.             point[3].y += c->calbox_ys[sm];
  217.         }
  218.     set_color(COL_STD);
  219.  
  220.                             /* weekday names */
  221.     j = c->sunday_first ? 6 : 0;
  222.     XSetFont(display, gc, font[sm ? FONT_NOTE : FONT_STD]->fid);
  223.     for (i=0; i < 7; i++, j++)
  224.         XDrawString(display, window, gc,
  225.             c->calbox_marg[sm] + c->calbox_arrow[sm]
  226.                        + c->calbox_xs[sm] * i,
  227.             c->calbox_marg[sm] + c->calbox_title[sm] * 3/4,
  228.             weekday_name[j%7], strlen(weekday_name[j%7]));
  229.     
  230.     for (i=1; i < 32; i++)
  231.         draw_day(i);
  232. }
  233.  
  234.  
  235. /*
  236.  * draw one day box.
  237.  */
  238.  
  239. draw_day(day)
  240.     int            day;        /* 1..31 */
  241. {
  242.     Window            window;
  243.     char            buf[200];    /* julian, weeknum, holiday */
  244.     int            x, y;        /* position in calendar */
  245.     int            jul;        /* julian date of daybox */
  246.     int            daynum_xs;    /* width of day# in pixels */
  247.     BOOL            leftedge;    /* in leftmost daybox? */
  248.     BOOL            weekend;    /* saturday or sunday? */
  249.     BOOL            today;        /* is this today's box? */
  250.     struct holiday        *hp, *shp;    /* to check for holidays */
  251.     char            *errmsg;    /* holiday parser error */
  252.     int            sm = config.smallmonth;
  253. #ifdef JAPAN
  254.     int            ji, jlen, jpixlen, jdeltax;
  255.     XChar2b            jstr[50];
  256. #endif
  257.  
  258.     if (!mainmenu.cal || !day_to_pos(&x, &y, day))
  259.         return;
  260.  
  261.     window = XtWindow(mainmenu.cal);
  262.     weekend = x == 6 || x == (config.sunday_first ? 0 : 5);
  263.     leftedge = x == 0;
  264.     daynum_xs = 5 + 2*font[FONT_DAY+sm]->per_char
  265.             ['0'- font[FONT_DAY+sm]->min_char_or_byte2].width;
  266.     x = config.calbox_marg[sm] + x * config.calbox_xs[sm] + 3 +
  267.                      config.calbox_arrow[sm];
  268.     y = config.calbox_marg[sm] + y * config.calbox_ys[sm] + 3 +
  269.                      config.calbox_title[sm];
  270.     today = set_day_bkg_color(day);
  271.     XFillRectangle(display, window, gc, x, y, config.calbox_xs[sm]-3,
  272.                           config.calbox_ys[sm]-3);
  273.     sprintf(buf, "%d", day);
  274.     XSetFont(display, gc, font[FONT_DAY+sm]->fid);
  275.  
  276.     if (errmsg = parse_holidays(curr_year, FALSE))
  277.         create_error_popup(mainmenu.cal, 0, errmsg);
  278.     jul = monthbegin[curr_month] + day-1 +(curr_month>1 && !(curr_year&3));
  279.     hp  =    &holiday[jul];
  280.     shp = &sm_holiday[jul];
  281.  
  282.     set_color( hp->daycolor    ?  hp->daycolor :
  283.           shp->daycolor    ? shp->daycolor :
  284.           weekend    ? COL_WEEKEND    : COL_WEEKDAY);
  285.  
  286.     XDrawString(display, window, gc,
  287.         x+2, y+font[FONT_DAY+sm]->max_bounds.ascent, buf, strlen(buf));
  288.  
  289.     if (config.julian || config.weeknum) {
  290.         int wkday, weeknum;
  291.         (void)date_to_time(day, curr_month, curr_year,
  292.                         &wkday, &jul, &weeknum);
  293.         *buf = 0;
  294.         if (config.weeknum && leftedge)
  295.             sprintf(buf, "(%d)", weeknum+1);
  296.         if (config.julian)
  297.             sprintf(buf+strlen(buf), "%d", jul+1);
  298.         truncate_string(buf, config.calbox_xs[sm] - 3 - daynum_xs,
  299.                                 FONT_NOTE);
  300.         XSetFont(display, gc, font[FONT_NOTE]->fid);
  301.         XDrawString(display, window, gc,
  302.             x + daynum_xs,
  303.             y + font[FONT_NOTE]->max_bounds.ascent,
  304.                             buf, strlen(buf));
  305.  
  306.     }
  307.     if (shp->string && (!config.julian && !config.weeknum ||
  308.                 font[FONT_DAY+sm]->max_bounds.ascent >
  309.                 font[FONT_NOTE]->max_bounds.ascent * 2)) {
  310.         strncpy(buf, shp->string, sizeof(buf)-1);
  311.         buf[sizeof(buf)-1] = 0;
  312. #ifndef JAPAN
  313.         truncate_string(buf, config.calbox_xs[sm] - 3 - daynum_xs,
  314.                                 FONT_NOTE);
  315. #endif
  316.         if (shp->stringcolor)
  317.             set_color(shp->stringcolor);
  318.         else if (shp->daycolor)
  319.             set_color(shp->daycolor);
  320.         XSetFont(display, gc, font[FONT_NOTE]->fid);
  321. #ifdef JAPAN
  322.         XSetFont(display, jgc, font[FONT_JNOTE]->fid);
  323.         ji = mixedstrtok(jstr, buf);
  324.         jpixlen = config.calbox_xs[sm] - 3 - daynum_xs;
  325.         jdeltax = 0;
  326.         do {
  327.             if (ji < 0) {
  328.                 fprintf(stderr, "String conversion error.\n");
  329.                 break;
  330.             }
  331.             if (ji == 0)
  332.                 break;
  333.             jlen = strlen((char *)jstr);
  334.             if (ji == 1) {
  335.                 ji = XTextWidth(font[FONT_NOTE],
  336.                             (char *)jstr, jlen);
  337.                 if (jpixlen < ji)
  338.                     jlen *= (double)jpixlen/(double)ji;
  339.                 XDrawString(display, window, gc,
  340.                     x + daynum_xs + jdeltax,
  341.                     y + font[FONT_DAY+sm]
  342.                             ->max_bounds.ascent,
  343.                     (char *)jstr, jlen);
  344.             } else {
  345.                 ji = XTextWidth16(font[FONT_JNOTE],
  346.                             (char *)jstr, jlen/2);
  347.                 if (jpixlen < ji)
  348.                     jlen *= (double)jpixlen/(double)ji;
  349.                 XDrawString16(display, window, jgc,
  350.                       x + daynum_xs + jdeltax,
  351.                       y + font[FONT_DAY+sm]
  352.                             ->max_bounds.ascent,
  353.                       jstr, jlen/2);
  354.             }
  355.             jdeltax += ji;
  356.             jpixlen -= ji;
  357.         } while (jpixlen > 0 && (ji = mixedstrtok(jstr, NULL)));
  358. #else
  359.         XDrawString(display, window, gc,
  360.             x + daynum_xs,
  361.             y + font[FONT_DAY+sm]->max_bounds.ascent,
  362.                             buf, strlen(buf));
  363. #endif
  364.     }
  365.     set_color(COL_STD);
  366.     draw_day_notes(day);
  367.     if (today && config.frame_today) {
  368.         XDrawRectangle(display, window, gc, x+1, y+1,
  369.                    config.calbox_xs[sm]-6, config.calbox_ys[sm]-6);
  370.         XDrawRectangle(display, window, gc, x+2, y+2,
  371.                    config.calbox_xs[sm]-8, config.calbox_ys[sm]-8);
  372.     }
  373. }
  374.  
  375.  
  376. /*
  377.  * draw (or undraw) the notes in a day box. Looks up the day in the database.
  378.  */
  379.  
  380. draw_day_notes(day)
  381.     int            day;        /* 1..31 */
  382. {
  383.     BOOL            today;        /* TRUE: it's today's daybox */
  384.     struct tm        *tm;        /* for daylight-saving tzone */
  385.     time_t            tod;        /* current time-of-day */
  386.     time_t            daytime;    /* time of day box, in sec */
  387.     BOOL            found;        /* TRUE if lookup succeeded */
  388.     struct lookup        lookup;        /* result of entry lookup */
  389.     register struct entry    *ep;        /* ptr to entry in mainlist */
  390.     int            x, y;        /* position in calendar */
  391.     int            xo, i;        /* for aligning ':' in time */
  392.     int            ye;        /* bottom limit of day box */
  393.     int            ys;        /* height of a text line */
  394.     char            buf[100];    /* string buffer (time/note) */
  395.     int            jul;        /* julian date of daybox */
  396.     struct holiday        *hp;        /* holiday info for this day */
  397.     char            *errmsg;    /* parser error */
  398.     Window            window;
  399.     int            sm = config.smallmonth;
  400. #ifdef JAPAN
  401.     int            ji, jlen, jpixlen, jdeltax;
  402.     XChar2b            jstr[50];
  403. #endif
  404.  
  405.     if (!mainmenu.cal)
  406.         return;
  407.  
  408.     window = XtWindow(mainmenu.cal);
  409.     tod    = get_time();
  410.     tm     = time_to_tm(tod);
  411.     today  = day        == tm->tm_mday &&
  412.          curr_month == tm->tm_mon  &&
  413.          curr_year  == tm->tm_year;
  414.  
  415.     if (!day_to_pos(&x, &y, day) ||
  416.         !(daytime = date_to_time(day, curr_month, curr_year, 0, 0, 0)))
  417.         return;
  418.  
  419.     x  = config.calbox_marg[sm] + x * config.calbox_xs[sm] + 3 +
  420.                         config.calbox_arrow[sm];
  421.     y  = config.calbox_marg[sm] + y * config.calbox_ys[sm] + 3 +
  422.                         config.calbox_title[sm];
  423.     ye = y + config.calbox_ys[sm] - 3;
  424. #ifdef JAPAN
  425.     ys = font[FONT_JNOTE]->max_bounds.ascent +
  426.          font[FONT_JNOTE]->max_bounds.descent/2;
  427.     if (ys < font[FONT_NOTE]->max_bounds.ascent +
  428.          font[FONT_NOTE]->max_bounds.descent/2)
  429. #endif
  430.     ys = font[FONT_NOTE]  ->max_bounds.ascent +
  431.          font[FONT_NOTE]  ->max_bounds.descent/2;
  432.     y += font[FONT_DAY+sm]->max_bounds.ascent + (ye - y) % ys / 2;
  433.  
  434.     (void)set_day_bkg_color(day);
  435.     XFillRectangle(display, window, gc, x,y, config.calbox_xs[sm]-3, ye-y);
  436.     XSetFont(display, gc,  font[FONT_NOTE]->fid);
  437. #ifdef JAPAN
  438.     XSetFont(display, jgc, font[FONT_JNOTE]->fid);
  439. #endif
  440.  
  441.     if (errmsg = parse_holidays(curr_year, FALSE))
  442.         create_error_popup(mainmenu.cal, 0, errmsg);
  443.     jul = monthbegin[curr_month] + day-1 + (curr_month>1 && !(curr_year&3));
  444.     hp  =    &holiday[jul];
  445. #ifdef JAPAN
  446.     if (hp->string && *hp->string &&
  447.             y + ((font[FONT_NOTE ]->max_bounds.descent <
  448.                   font[FONT_JNOTE]->max_bounds.descent ?
  449.                   font[FONT_JNOTE]->max_bounds.descent :
  450.                   font[FONT_NOTE ]->max_bounds.descent)<<2) <= ye){
  451.         
  452.         y += (font[FONT_NOTE ]->max_bounds.ascent <
  453.               font[FONT_JNOTE]->max_bounds.ascent) ?
  454.               font[FONT_JNOTE]->max_bounds.ascent :
  455.               font[FONT_NOTE ]->max_bounds.ascent;
  456.  
  457.         set_color(hp->stringcolor ? hp->stringcolor : COL_NOTE);
  458.  
  459.         ji = mixedstrtok(jstr, hp->string);
  460.         jpixlen = config.calbox_xs[sm] - 3;
  461.         jdeltax = 0;
  462.         do {
  463.             if (ji < 0) {
  464.                 fprintf(stderr, "String conversion error.\n");
  465.                 break;
  466.             }
  467.             if (ji == 0)
  468.                 break;
  469.             jlen = strlen((char *)jstr);
  470.             if (ji == 1) {
  471.                 ji = XTextWidth(font[FONT_NOTE],
  472.                             (char *)jstr, jlen);
  473.                 if (jpixlen < ji)
  474.                     jlen *= (double)jpixlen/(double)ji;
  475.                 XDrawString(display, window, gc, x+jdeltax+2,
  476.                             y, (char *)jstr, jlen);
  477.             } else {
  478.                 ji = XTextWidth16(font[FONT_JNOTE],
  479.                             (char *)jstr, jlen/2);
  480.                 if (jpixlen < ji)
  481.                 jlen *= (double)jpixlen/(double)ji;
  482.                 XDrawString16(display, window, jgc,
  483.                         x+jdeltax+2, y, jstr, jlen/2);
  484.             }
  485.             jdeltax += ji;
  486.             jpixlen -= ji;
  487.         } while (jpixlen > 0 && (ji = mixedstrtok(jstr, NULL)));
  488.  
  489.         y += (font[FONT_NOTE ]->max_bounds.descent <
  490.               font[FONT_JNOTE]->max_bounds.descent) ?
  491.               font[FONT_JNOTE]->max_bounds.descent/2 :
  492.               font[FONT_NOTE ]->max_bounds.descent/2;
  493.     }
  494. #else
  495.     if (hp->string && *hp->string &&
  496.                 y + font[FONT_NOTE]->max_bounds.descent
  497.                   + font[FONT_NOTE]->max_bounds.descent <= ye){
  498.         strncpy(buf, hp->string, sizeof(buf)-1);
  499.         truncate_string(buf, config.calbox_xs[sm] - 3, FONT_NOTE);
  500.         y += font[FONT_NOTE]->max_bounds.ascent;
  501.         set_color(hp->stringcolor ? hp->stringcolor : COL_NOTE);
  502.         XDrawString(display, window, gc, x+2, y, buf, strlen(buf));
  503.         y += font[FONT_NOTE]->max_bounds.descent/2;
  504.     }
  505. #endif
  506.  
  507.     found = lookup_entry(&lookup, mainlist, daytime, TRUE, FALSE);
  508.     for (; found; found = lookup_next_entry(&lookup)) {
  509.  
  510.         ep = &mainlist->entry[lookup.index];
  511.         if (ep->note && (*ep->note == '-' || *ep->note == '='))
  512.             continue;
  513.         if (lookup.index >= mainlist->nentries    ||
  514.             lookup.trigger <  daytime        ||
  515.             lookup.trigger >= daytime + 86400)
  516.             break;
  517.         if (today && config.nopast &&
  518.             lookup.trigger < tod   &&
  519.             !ep->notime)
  520.             continue;
  521.  
  522.         if (y + font[FONT_NOTE]->max_bounds.descent
  523.               + font[FONT_NOTE]->max_bounds.descent > ye) {
  524.             int xe = x + config.calbox_xs[sm] -3;
  525.             set_color(COL_NOTE);
  526.             XFillRectangle(display, window, gc, xe-4,  ye-3, 2, 2);
  527.             XFillRectangle(display, window, gc, xe-8,  ye-3, 2, 2);
  528.             XFillRectangle(display, window, gc, xe-12, ye-3, 2, 2);
  529.             break;
  530.         }
  531.         if (ep->notime)
  532.             sprintf(buf, "%.90s",  mknotestring(ep));
  533.         else
  534.             sprintf(buf, "%s %.90s", mktimestring(lookup.trigger,
  535.                         FALSE), mknotestring(ep));
  536. #ifdef JAPAN
  537.         y += (font[FONT_NOTE ]->max_bounds.ascent <
  538.               font[FONT_JNOTE]->max_bounds.ascent) ?
  539.               font[FONT_JNOTE]->max_bounds.ascent :
  540.               font[FONT_NOTE ]->max_bounds.ascent;
  541.  
  542.         set_color(ep->suspended ? COL_NOTEOFF : COL_NOTE);
  543.         ji = mixedstrtok(jstr, buf);
  544.         jpixlen = config.calbox_xs[sm] - 3;
  545.         jdeltax = 0;
  546.         do {
  547.             if (ji < 0) {
  548.                 fprintf(stderr, "String conversion error.\n");
  549.                 break;
  550.             }
  551.             if (ji == 0)
  552.                 break;
  553.             jlen = strlen((char *)jstr);
  554.             if (ji == 1) {
  555.                 ji = XTextWidth(font[FONT_NOTE],
  556.                             (char *)jstr, jlen);
  557.                 if (jpixlen < ji)
  558.                     jlen *= (double)jpixlen/(double)ji;
  559.                 XDrawString(display, window, gc, x+jdeltax+2,
  560.                             y, (char *)jstr, jlen);
  561.             } else {
  562.                 ji = XTextWidth16(font[FONT_JNOTE],
  563.                             (char *)jstr, jlen/2);
  564.                 if (jpixlen < ji)
  565.                     jlen *= (double)jpixlen/(double)ji;
  566.                 XDrawString16(display, window, jgc,
  567.                         x+jdeltax+2, y, jstr, jlen/2);
  568.             }
  569.             jdeltax += ji;
  570.             jpixlen -= ji;
  571.         } while (jpixlen > 0 && (ji = mixedstrtok(jstr, NULL)));
  572. #else
  573.         truncate_string(buf, config.calbox_xs[sm] - 5, FONT_NOTE);
  574.         y += font[FONT_NOTE]->max_bounds.ascent;
  575.         set_color(ep->suspended ? COL_NOTEOFF : COL_NOTE);
  576.         i  = font[FONT_NOTE]->min_char_or_byte2;
  577.         xo = font[FONT_NOTE]->per_char['0'  - i].width -
  578.              font[FONT_NOTE]->per_char[*buf - i].width;
  579.         if (xo < 0) xo = 0;
  580.         XDrawString(display, window, gc, x+2+xo, y, buf, strlen(buf));
  581. #endif
  582.         y += font[FONT_NOTE]->max_bounds.descent/2;
  583.     }
  584.     set_color(COL_STD);
  585. }
  586.  
  587.  
  588. /*
  589.  * truncate <string> such that it is not longer than <len> pixels when
  590.  * drawn with font <sfont>, by storing \0 somewhere in the string.
  591.  */
  592.  
  593. truncate_string(string, len, sfont)
  594.     register unsigned char *string;    /* string to truncate */
  595.     register int    len;        /* max len in pixels */
  596.     int        sfont;        /* font of string */
  597. {
  598.     while (*string) {
  599.         len -= font[sfont]->per_char
  600.                [*string - font[sfont]->min_char_or_byte2].width;
  601.         if (len < 0)
  602.             *string = 0;
  603.         else
  604.             string++;
  605.     }
  606. }
  607.  
  608.  
  609. static BOOL set_day_bkg_color(day)
  610.     int            day;        /* 1..31 */
  611. {
  612.     struct tm        *tm;
  613.  
  614.     tm = time_to_tm(get_time());
  615.     if      (day        == edit_day    &&
  616.            curr_year  == edit_year   &&
  617.            curr_month == edit_month) {
  618.                         set_color(COL_CALACT);
  619.                         return(FALSE);
  620.  
  621.     } else if (day        == tm->tm_mday &&
  622.            curr_month == tm->tm_mon  &&
  623.            curr_year  == tm->tm_year) {
  624.                         set_color(COL_CALTODAY);
  625.                         return(TRUE);
  626.     } else {
  627.                         set_color(COL_CALSHADE);
  628.                         return(FALSE);
  629.     }
  630. }
  631.  
  632.  
  633. /*-------------------------------------------------- low-level --------------*/
  634. /*
  635.  * day/month/year to time. Return 0 if something is wrong.
  636.  * Also return the weekday, julian date, and week number of that date.
  637.  * Note that *wkday counts from 0=sunday to 6=saturday.
  638.  */
  639.  
  640. time_t date_to_time(day, month, year, wkday, julian, weeknum)
  641.     int day, month, year, *wkday, *julian, *weeknum;
  642. {
  643.     struct tm        tm;
  644.     time_t            time;
  645.  
  646.     tm.tm_sec   = 0;
  647.     tm.tm_min   = 0;
  648.     tm.tm_hour  = 0;
  649.     tm.tm_mday  = day;
  650.     tm.tm_mon   = month;
  651.     tm.tm_year  = year;
  652.     time = tm_to_time(&tm);
  653.     if (wkday)
  654.         *wkday   = tm.tm_wday;
  655.     if (julian)
  656.         *julian  = tm.tm_yday;
  657.     if (weeknum)
  658. #ifdef FULLWEEKS
  659.         *weeknum = tm.tm_yday / 7;
  660. #else
  661.         *weeknum = tm.tm_yday ? ((tm.tm_yday - 1) /7) + 1: 0;
  662. #endif
  663.     return(time == -1 || day != tm.tm_mday ? 0 : time);
  664. }
  665.  
  666.  
  667. day_to_pos(x, y, day)
  668.     int            *x, *y;        /* returned box, 0..6/0..5 */
  669.     int            day;        /* 1..31 */
  670. {
  671.     int            wkday;
  672.  
  673.     if (!date_to_time(day, curr_month, curr_year, &wkday, 0, 0))
  674.         return(FALSE);
  675.     *x = config.sunday_first ?  wkday : (wkday + 6) % 7;
  676.     *y = (day-1 - *x + 6) / 7;
  677.     return(TRUE);
  678. }
  679.  
  680.  
  681. pos_to_day(day, x, y)
  682.     int            *day;        /* returned day #, 1..31 */
  683.     int            x, y;        /* pixel pos in drawable */
  684. {
  685.     int            xtest, ytest;
  686.     int            sm = config.smallmonth;
  687.  
  688.     (void)day_to_pos(&xtest, &ytest, 1);
  689.     x -= config.calbox_marg[sm] + config.calbox_arrow[sm];
  690.     y -= config.calbox_marg[sm] + config.calbox_title[sm];
  691.     if (x < 0 || y < 0)
  692.         return(FALSE);
  693.     x /= config.calbox_xs[sm];
  694.     y /= config.calbox_ys[sm];
  695.     *day = y * 7 + x - xtest + 1;
  696.     if (*day < 1)
  697.         return(FALSE);
  698.     return(day_to_pos(&xtest, &ytest, *day));
  699. }
  700.  
  701.  
  702. /*
  703.  * the rest of this file is for Japanese version only. Written by Ogura
  704.  * Yoshito, like everything else enclosed in #ifdef JAPAN and #endif.
  705.  */
  706.  
  707. #ifdef JAPAN
  708. static int mixedstrtok(jisstr, sjstr)
  709.     char            *jisstr, *sjstr;
  710. {
  711.     static int        stat;
  712.     static unsigned char    *sptr = NULL;
  713.     unsigned char        *dptr = (unsigned char *)jisstr;
  714.     unsigned short        wc;
  715.     int            prev_ct = CT_ASC;
  716.  
  717.     if (sjstr != NULL)
  718.         stat = chkctype(*(char *)
  719.                 (sptr = (unsigned char *)sjstr), CT_ASC);
  720.     if (sptr == NULL) {
  721.         *dptr = '\0';
  722.         return (-1);    /* Illegal pointer. */
  723.     }
  724.     while (*sptr != '\0') {
  725.         switch (prev_ct = chkctype(*sptr, prev_ct)) {
  726.           case CT_ASC:
  727.             if (stat != CT_ASC)
  728.                 goto STATCHG;
  729.             *dptr++ = *sptr++;
  730.             break;
  731.           case CT_KJ1:
  732.             if (stat == CT_ASC)
  733.                 goto STATCHG;
  734.             wc = *sptr++ << 8;
  735.             break;
  736.           case CT_KJ2:
  737.             if (stat == CT_ASC)
  738.                 goto STATCHG;
  739.             wc |= *sptr++;
  740.             wc = (*kanji2jis)(wc);
  741.                     /* kanji2jis == euc2jis or sjis2jis */
  742.             *dptr++ = wc >> 8;
  743.             *dptr++ = wc;
  744.             break;
  745.           default:
  746.             *dptr = '\0';
  747.             return (-1);    /* Parse error. */
  748.         }
  749.     }
  750. STATCHG:
  751.     *dptr = '\0';
  752.     if (jisstr != (char *)dptr) {
  753.                 /* Bit1 == 1 if SJIS string is copied.    */
  754.         wc = stat;
  755.         stat = prev_ct;
  756.         return (wc == CT_ASC) ? 1 : 2;
  757.     }
  758.     return 0;
  759. }
  760.  
  761.  
  762. int mixedstrlen_in_pixels(sjstr, stp, ascfont, jfont)
  763.     char            *sjstr;
  764.     strpack            *stp;
  765.     int            ascfont, jfont;
  766. {
  767.     register int        jlen, plen = 0, i = 0, j = 0, k;
  768.     register unsigned char    *cpyptr, *strpool = stp->strptr;
  769.     unsigned char        jstr[100];
  770.  
  771.     k = mixedstrtok(cpyptr = jstr, sjstr);
  772.     do {
  773.         if (k <= 0) {
  774.             if (k != 0)
  775.                 fprintf(stderr, "String conversion error.\n");
  776.             stp[i].strptr = NULL;
  777.             break;
  778.         }
  779.         if (j+1+(jlen = stp[i].length = strlen(jstr))>=MAXPARTIALCHAR){
  780.             if (jlen = stp[i].length = (MAXPARTIALCHAR-j-1 & ~1)) {
  781.                 for (stp[i].strptr = strpool + j;
  782.                         j < MAXPARTIALCHAR-1; j++)
  783.                     strpool[j] = *cpyptr++;
  784.                 strpool[j] = '\0';
  785.                 if (k == 1) {
  786.                     stp[i].asciistr = True;
  787.                     plen += stp[i].pixlen = XTextWidth(
  788.                             font[ascfont], jstr, jlen);
  789.                 } else {
  790.                     stp[i].asciistr = False;
  791.                     plen += stp[i].pixlen = XTextWidth16(
  792.                             font[jfont],
  793.                             (XChar2b *)jstr, jlen/2);
  794.                 }
  795.                 if (++i < MAXPARTIALSTRING)
  796.                     stp[i].strptr = NULL;
  797.             } else
  798.                 stp[i].strptr = NULL;
  799.             break;
  800.         }
  801.         stp[i].strptr = strpool + j;
  802.         while (*cpyptr != '\0')
  803.             strpool[j++] = *cpyptr++;
  804.         strpool[j++] = '\0';
  805.         if (k == 1) {
  806.             stp[i].asciistr = True;
  807.             plen += stp[i].pixlen = XTextWidth(font[ascfont],
  808.                             jstr, jlen);
  809.         } else {
  810.             stp[i].asciistr = False;
  811.             plen += stp[i].pixlen = XTextWidth16(font[jfont],
  812.                         (XChar2b * )jstr, jlen / 2);
  813.         }
  814.     } while (++i < MAXPARTIALSTRING  && 
  815.                 ((k = mixedstrtok(cpyptr = jstr, NULL)) ||
  816.                         ((stp[i].strptr = NULL), 0)));
  817.     return plen;
  818. }
  819. #endif
  820.